package org.geogebra.desktop.gui.util;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;

/**
 * Layout manager which stretches all component to the full possible width, but
 * unlike GridLayout does not enforce any height. Unncessary space is left empty
 * at the bottom of the container.
 */
public class FullWidthLayout implements LayoutManager {
	private int vgap;
	private int minWidth = 0;
	private int minHeight = 0;
	private int preferredWidth = 0;
	private int preferredHeight = 0;
	private boolean sizeUnknown = true;

	/**
	 * Creates a new instance of the layout manager with a vertical gap of 5px.
	 */
	public FullWidthLayout() {
		this(5);
	}

	/**
	 * Creates a new instance of the layout manager.
	 * 
	 * @param vgap
	 *            gap between two components in px
	 */
	public FullWidthLayout(int vgap) {
		this.vgap = vgap;
	}

	/**
	 * Calculate the minimum and preferred size of the passed container.
	 * 
	 * @param parent container
	 */
	private void calculateSizes(Container parent) {
		preferredWidth = 0;
		preferredHeight = 0;
		minWidth = 0;
		minHeight = 0;

		Dimension pref = null, min = null;
		for (int i = 0; i < parent.getComponentCount(); i++) {
			Component c = parent.getComponent(i);

			if (c.isVisible()) {
				pref = c.getPreferredSize();
				min = c.getMinimumSize();

				preferredHeight += (i > 0 ? vgap : 0) + pref.height;
				preferredWidth = Math.max(pref.width, preferredWidth);

				minWidth = Math.max(min.width, minWidth);
				minHeight += (i > 0 ? vgap : 0) + min.height;
			}
		}
	}

	/**
	 * @return The preferred size of the container.
	 */
	@Override
	public Dimension preferredLayoutSize(Container parent) {
		calculateSizes(parent);
		sizeUnknown = false;

		Insets insets = parent.getInsets();
		return new Dimension(preferredWidth + insets.left + insets.right,
				preferredHeight + insets.top + insets.bottom);
	}

	/**
	 * @return The minimum size of the container.
	 */
	@Override
	public Dimension minimumLayoutSize(Container parent) {
		if (sizeUnknown) {
			calculateSizes(parent);
			sizeUnknown = false;
		}

		Insets insets = parent.getInsets();
		return new Dimension(minWidth + insets.left + insets.right,
				minHeight + insets.top + insets.bottom);
	}

	/**
	 * Layout components.
	 */
	@Override
	public void layoutContainer(Container parent) {
		Insets insets = parent.getInsets();

		int maxWidth = parent.getWidth() - (insets.left + insets.right);
		int y = insets.top;

		if (sizeUnknown) {
			calculateSizes(parent);
		}

		for (int i = 0; i < parent.getComponentCount(); i++) {
			Component c = parent.getComponent(i);

			if (c.isVisible()) {
				Dimension pref = c.getPreferredSize();

				if (i > 0) {
					y += vgap;
				}

				c.setBounds(insets.left, y, maxWidth, pref.height);

				y += pref.height;
			}
		}
	}

	/**
	 * Not implemented.
	 */
	@Override
	public void addLayoutComponent(String name, Component comp) {
		// not needed
	}

	/**
	 * Not implemented.
	 */
	@Override
	public void removeLayoutComponent(Component comp) {
		// not needed
	}

	/**
	 * The class name and vertical gap as string.
	 */
	@Override
	public String toString() {
		return getClass().getName() + "[vgap=" + vgap + "]";
	}
}
